<?php
declare(strict_types=1);

namespace App\Service;

use App\Model\Dao\RiskRuleCollectionConnDao;
use App\Model\Dao\RiskRuleInfoDao;
use App\Model\Enum\RiskRuleCollectionTypeEnum;
use App\Utils\CustomUtils;
use App\Utils\StringUtils;
use Hyperf\Database\Query\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use App\Model\Dao\RiskRuleCollectionDao;
use App\Exception\XZXValidationException;
use App\Constants\XZXResponseCode;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Coroutine;
use App\Utils\DateUtils;
use Hyperf\Utils\Arr;

class RiskRuleCollectionService {

    /**
     * @Inject()
     * @var RiskRuleCollectionDao
     */
    private $RiskRuleCollectionDao;

    /**
     * @Inject()
     * @var RiskRuleCollectionConnDao
     */
    private $RiskRuleCollectionConnDao;

    /**
     * @Inject()
     * @var RiskRuleInfoDao
     */
    private $RiskRuleInfoDao;

    /**
     * @Inject()
     * @var SyncService
     */
    private $SyncService;

    /**
     * 列表
     *
     * @param array $param
     *
     * @return array
     */
    public function list (array $param) {

        $limit = Arr::pull($param, 'limit', null);
        $page  = Arr::pull($param, 'page', null);

        $total = $this->RiskRuleCollectionDao->getCount($param);
        $list  = $this->RiskRuleCollectionDao->getList($param, $page, $limit);

        $list = CustomUtils::formatCreateTime($list);
        foreach ($list as $k => $v) {
            // $v['createTime'] = xeGetDateTime($v['createTime']);
            $v['strType']    = $this->RiskRuleCollectionDao->strType($v['type']);
            $v['strStatus']  = $this->RiskRuleCollectionDao->strStatus($v['status']);
            $list[$k] = $v;
        }
        $data = [
            'total' => $total,
            'list'  => $list,
        ];

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), $data);
    }

    /**
     * 详情
     *
     * @param $param
     *
     * @return array
     */
    public function get ($param) {

        $info = $this->RiskRuleCollectionDao->get($param['id']);

        if (!$info) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        // 关联数据
        $conn = $this->RiskRuleCollectionConnDao->getWhereList([
            'collectionId' => $info['id'],
            'status'       => 1,
        ]);
        $conn = array_column($conn, 'ruleId');
        if (empty($conn)) {
            $ruleList = [];
        }
        else {
            $ruleList = $this->RiskRuleInfoDao->getWhereList(function (Builder $query) use ($conn) {
                $query->where('status', 1);
                $query->whereIn('id', $conn);
            });
        }

        $info             = CustomUtils::formatCreateTime($info);
        $info['ruleList'] = CustomUtils::formatCreateTime($ruleList);

        $data = $info;

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), $data);
    }

    /**
     * 从参数过滤得到添加/更新数组
     *
     * @param $param
     *
     * @return array
     */
    protected function _filterUpdate ($param) {

        $update = Arr::only($param, [
            'status',
            'collectionName',
            'type',
        ]);

        return $update;
    }

    protected function _setConn ($id, $param) {

        // 为传入该字段, 无需处理
        if (!Arr::exists($param, 'conn')) {
            return true;
        }

        // 查询有效的值
        $conn = Arr::pull($param, 'conn', []);
        $conn = array_unique($conn);

        if (!empty($conn)) {
            $list = $this->RiskRuleInfoDao->getWhereList(function (Builder $query) use ($conn) {
                $query->whereIn('id', $conn);
            });
            $conn = array_column($list, 'id');
        }

        Db::beginTransaction();

        try {
            // 全删
            $this->RiskRuleCollectionConnDao->delWhere(['collectionId' => $id]);

            // 全增
            $update                 = Arr::only($param, ['createBy', 'updateBy']);
            $update['collectionId'] = $id;

            $updateList = [];
            foreach ($conn as $ruleId) {
                array_push($updateList, array_merge($update, [
                    'ruleId' => $ruleId,
                    'id'     => StringUtils::uuidV4(),
                ]));
            }

            $this->RiskRuleCollectionConnDao->add($updateList);

        } catch (\Exception $err) {
            Db::rollBack();
            throw $err;
        }

        Db::commit();
    }

    /**
     * 添加
     *
     * @param $param
     *
     * @return array
     * @throws \Throwable
     */
    public function add ($param) {

        $type = $param['type'];

        if ($type == RiskRuleCollectionTypeEnum::GLOBAL) {
            if ($this->RiskRuleCollectionDao->getWhereCount(['type' => $type]) > 0) {
                throw new \Exception('全局类型风控集合只能添加一个');
            }
        }

        $update = $this->_filterUpdate($param);
        $update = array_merge($update, Arr::only($param, ['createBy', 'updateBy']));

        $id           = StringUtils::uuidV4();
        $update['id'] = $id;

        Db::beginTransaction();

        try {

            $this->RiskRuleCollectionDao->insert($update);
            $this->_setConn($id, $param);

        } catch (\Throwable $err) {
            Db::rollBack();
            throw $err;
        }

        Db::commit();

        $data = ['id' => $update['id']];

        return CustomUtils::buildSuccess($data);
    }

    /**
     * 编辑
     *
     * @param $param
     *
     * @return array
     */
    public function edit ($param) {

        unset($param['type']); // 类型添加后不能修改

        $id = Arr::pull($param, 'id');


        $info = $this->RiskRuleCollectionDao->get($id);
        if (!$info) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        $update = $this->_filterUpdate($param);
        $update = array_merge($update, Arr::only($param, ['updateBy']));

        Db::beginTransaction();

        try {

            $this->RiskRuleCollectionDao->update($id, $update);

            $this->_setConn($id, $param);

            $this->_clearCache($info['type'], $id);

        } catch (\Exception $err) {
            Db::rollBack();
            throw $err;
        }

        Db::commit();


        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), CustomUtils::xzxEmptyObject());
    }

    protected function _clearCache ($type, $id) {
        $this->SyncService->syncRiskRuleCollection($id);
    }

    /**
     * 删除
     *
     * @param $param
     *
     * @return array
     */
    public function del ($param) {

        $id = Arr::pull($param, 'id');

        $result = $this->RiskRuleCollectionDao->get($id);

        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        $this->RiskRuleCollectionDao->del($id, false);

        $this->_clearCache($result['type'], $id);

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE, XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE), CustomUtils::xzxEmptyObject());
    }

    /**
     * 类型下拉框
     *
     * @param $params
     *
     * @return array
     */
    public function typeOptions ($params) {
        $data = RiskRuleCollectionTypeEnum::born()->getOptions();
        return CustomUtils::buildSuccess($data);
    }

    public function options ($params) {

        $list = $this->RiskRuleCollectionDao->getWhereList(function (Builder $query) use ($params) {

            $query->where('status', 1);
            !empty($params['search']) && $query->where('collectionName', 'like', "%{$params['search']}%");
            !empty($params['type']) && $query->where('type', $params['type']);
        });

        $list = array_map(function ($item) {
            return [
                'value' => $item['id'],
                'label' => $item['collectionName'],
                'type'  => $item['type'],
            ];
        }, $list);

        $data = $list;

        return CustomUtils::buildSuccess($data);
    }
}
